
#include "config.hpp"

#include "atr/initializer_list.hpp"
#include "atr/containers/assign.hpp"
#include "atr/containers/capacity.hpp"
#include "atr/containers/iterators.hpp"

#include "containers/capacity_test.hpp"
#include "containers/iterators_test.hpp"

template <typename ... Types> 
struct TestList 
    : public atr::__::__capacity<Types...>
    , public atr::__::__iterators<TestList, Types...>
    {};

template <typename ... Types>
struct initializer_list_proxy 
    : public initializer_list<TestList, 1, Types...>
    , public atr::__::__assign<initializer_list_proxy>
    {};

using namespace atr;

namespace 
{
    INSTANTIATE_TYPED_TEST_CASE_P(Initializer_List, CapacityTest, initializer_list_proxy<>);
    INSTANTIATE_TYPED_TEST_CASE_P(Initializer_List, IteratorsTest, initializer_list_proxy<>);
}

TEST(InitializerListTest, Empty_SingleElement)
{
    using T1 = initializer_list<TestList, 0, int>::type;
    using T2 = initializer_list<TestList, 0, long>::type;

    using E1 = TestList<>;
    using E2 = TestList<>;

    EXPECT_SAME( E1, T1 );
    EXPECT_SAME( E2, T2 );

    EXPECT_SAME( _size_t<0>, T1::size );
    EXPECT_SAME( _size_t<0>, T2::size );

    EXPECT_SAME( T1::begin, T1::end );
    EXPECT_SAME( T2::begin, T2::end );
}

TEST(InitializerListTest, NonEmpty_SingleElement)
{
    using T1 = initializer_list<TestList, 1, int>::type;
    using T2 = initializer_list<TestList, 2, long>::type;
    using T3 = initializer_list<TestList, 4, char>::type;

    using E1 = TestList<int>;
    using E2 = TestList<long, long>;
    using E3 = TestList<char, char, char, char>;


    EXPECT_SAME( E1, T1 );
    EXPECT_SAME( E2, T2 );
    EXPECT_SAME( E3, T3 );

    EXPECT_SAME( _size_t<1>, T1::size );
    EXPECT_SAME( _size_t<2>, T2::size );
    EXPECT_SAME( _size_t<4>, T3::size );

    EXPECT_SAME( T1::begin, T1::end::prev );
    EXPECT_SAME( T2::begin, T2::end::prev::prev );
}

TEST(InitializerListTest, Empty)
{
    using T1 = initializer_list<TestList, 0, int, char, long>::type;
    using T2 = initializer_list<TestList, 0, long, long, size_t, bool>::type;

    using E1 = TestList<>;
    using E2 = TestList<>;

    EXPECT_SAME( E1, T1 );
    EXPECT_SAME( E2, T2 );

    EXPECT_SAME( _size_t<0>, T1::size );
    EXPECT_SAME( _size_t<0>, T2::size );

    EXPECT_SAME( T1::begin, T1::end );
    EXPECT_SAME( T2::begin, T2::end );
}

TEST(InitializerListTest, NonEmpty)
{
    using T1 = initializer_list<TestList, 1, int, char, long>::type;
    using T2 = initializer_list<TestList, 2, long, char>::type;
    using T3 = initializer_list<TestList, 4, char, long, long>::type;

    using E1 = TestList<int, char, long>;
    using E2 = TestList<long, char, long, char>;
    using E3 = TestList<char, long, long, char, long, long, 
                        char, long, long, char, long, long>;


    EXPECT_SAME( E1, T1 );
    EXPECT_SAME( E2, T2 );
    EXPECT_SAME( E3, T3 );

    EXPECT_SAME( _size_t<3>, T1::size );
    EXPECT_SAME( _size_t<4>, T2::size );
    EXPECT_SAME( _size_t<12>, T3::size );

    EXPECT_SAME( T1::begin, T1::end::prev::prev::prev );
    EXPECT_SAME( T2::begin::next::next, T2::end::prev::prev );
}